summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/audio_core/renderer/command/command_generator.cpp2
-rw-r--r--src/audio_core/renderer/command/effect/aux_.cpp130
-rw-r--r--src/core/CMakeLists.txt2
-rw-r--r--src/core/hle/kernel/init/init_slab_setup.cpp2
-rw-r--r--src/core/hle/kernel/k_object_name.cpp102
-rw-r--r--src/core/hle/kernel/k_object_name.h86
-rw-r--r--src/core/hle/kernel/kernel.cpp14
-rw-r--r--src/core/hle/kernel/kernel.h8
-rw-r--r--src/core/hle/kernel/svc/svc_port.cpp54
-rw-r--r--src/video_core/engines/maxwell_3d.cpp4
-rw-r--r--src/video_core/host1x/codecs/codec.cpp2
-rw-r--r--src/yuzu/configuration/config.cpp1
-rw-r--r--src/yuzu/game_list.cpp1
-rw-r--r--src/yuzu/game_list.h1
-rw-r--r--src/yuzu/main.cpp10
15 files changed, 374 insertions, 45 deletions
diff --git a/src/audio_core/renderer/command/command_generator.cpp b/src/audio_core/renderer/command/command_generator.cpp
index 2ea50d128..fba84c7bd 100644
--- a/src/audio_core/renderer/command/command_generator.cpp
+++ b/src/audio_core/renderer/command/command_generator.cpp
@@ -46,7 +46,7 @@ void CommandGenerator::GenerateDataSourceCommand(VoiceInfo& voice_info,
while (destination != nullptr) {
if (destination->IsConfigured()) {
auto mix_id{destination->GetMixId()};
- if (mix_id < mix_context.GetCount()) {
+ if (mix_id < mix_context.GetCount() && mix_id != UnusedSplitterId) {
auto mix_info{mix_context.GetInfo(mix_id)};
command_buffer.GenerateDepopPrepareCommand(
voice_info.node_id, voice_state, render_context.depop_buffer,
diff --git a/src/audio_core/renderer/command/effect/aux_.cpp b/src/audio_core/renderer/command/effect/aux_.cpp
index e76db893f..c5650effa 100644
--- a/src/audio_core/renderer/command/effect/aux_.cpp
+++ b/src/audio_core/renderer/command/effect/aux_.cpp
@@ -4,6 +4,7 @@
#include "audio_core/renderer/adsp/command_list_processor.h"
#include "audio_core/renderer/command/effect/aux_.h"
#include "audio_core/renderer/effect/aux_.h"
+#include "core/core.h"
#include "core/memory.h"
namespace AudioCore::AudioRenderer {
@@ -19,10 +20,24 @@ static void ResetAuxBufferDsp(Core::Memory::Memory& memory, const CpuAddr aux_in
return;
}
- auto info{reinterpret_cast<AuxInfo::AuxInfoDsp*>(memory.GetPointer(aux_info))};
- info->read_offset = 0;
- info->write_offset = 0;
- info->total_sample_count = 0;
+ AuxInfo::AuxInfoDsp info{};
+ auto info_ptr{&info};
+ bool host_safe{(aux_info & Core::Memory::YUZU_PAGEMASK) <=
+ (Core::Memory::YUZU_PAGESIZE - sizeof(AuxInfo::AuxInfoDsp))};
+
+ if (host_safe) [[likely]] {
+ info_ptr = memory.GetPointer<AuxInfo::AuxInfoDsp>(aux_info);
+ } else {
+ memory.ReadBlockUnsafe(aux_info, info_ptr, sizeof(AuxInfo::AuxInfoDsp));
+ }
+
+ info_ptr->read_offset = 0;
+ info_ptr->write_offset = 0;
+ info_ptr->total_sample_count = 0;
+
+ if (!host_safe) [[unlikely]] {
+ memory.WriteBlockUnsafe(aux_info, info_ptr, sizeof(AuxInfo::AuxInfoDsp));
+ }
}
/**
@@ -40,11 +55,10 @@ static void ResetAuxBufferDsp(Core::Memory::Memory& memory, const CpuAddr aux_in
* @param update_count - If non-zero, send_info_ will be updated.
* @return Number of samples written.
*/
-static u32 WriteAuxBufferDsp(Core::Memory::Memory& memory, const CpuAddr send_info_,
- [[maybe_unused]] u32 sample_count, const CpuAddr send_buffer,
- const u32 count_max, std::span<const s32> input,
- const u32 write_count_, const u32 write_offset,
- const u32 update_count) {
+static u32 WriteAuxBufferDsp(Core::Memory::Memory& memory, CpuAddr send_info_,
+ [[maybe_unused]] u32 sample_count, CpuAddr send_buffer, u32 count_max,
+ std::span<const s32> input, u32 write_count_, u32 write_offset,
+ u32 update_count) {
if (write_count_ > count_max) {
LOG_ERROR(Service_Audio,
"write_count must be smaller than count_max! write_count {}, count_max {}",
@@ -52,6 +66,11 @@ static u32 WriteAuxBufferDsp(Core::Memory::Memory& memory, const CpuAddr send_in
return 0;
}
+ if (send_info_ == 0) {
+ LOG_ERROR(Service_Audio, "send_info_ is 0!");
+ return 0;
+ }
+
if (input.empty()) {
LOG_ERROR(Service_Audio, "input buffer is empty!");
return 0;
@@ -67,33 +86,47 @@ static u32 WriteAuxBufferDsp(Core::Memory::Memory& memory, const CpuAddr send_in
}
AuxInfo::AuxInfoDsp send_info{};
- memory.ReadBlockUnsafe(send_info_, &send_info, sizeof(AuxInfo::AuxInfoDsp));
+ auto send_ptr = &send_info;
+ bool host_safe = (send_info_ & Core::Memory::YUZU_PAGEMASK) <=
+ (Core::Memory::YUZU_PAGESIZE - sizeof(AuxInfo::AuxInfoDsp));
- u32 target_write_offset{send_info.write_offset + write_offset};
- if (target_write_offset > count_max || write_count_ == 0) {
+ if (host_safe) [[likely]] {
+ send_ptr = memory.GetPointer<AuxInfo::AuxInfoDsp>(send_info_);
+ } else {
+ memory.ReadBlockUnsafe(send_info_, send_ptr, sizeof(AuxInfo::AuxInfoDsp));
+ }
+
+ u32 target_write_offset{send_ptr->write_offset + write_offset};
+ if (target_write_offset > count_max) {
return 0;
}
u32 write_count{write_count_};
- u32 write_pos{0};
+ u32 read_pos{0};
while (write_count > 0) {
u32 to_write{std::min(count_max - target_write_offset, write_count)};
-
- if (to_write > 0) {
+ const auto write_addr = send_buffer + target_write_offset * sizeof(s32);
+ bool write_safe{(write_addr & Core::Memory::YUZU_PAGEMASK) <=
+ (Core::Memory::YUZU_PAGESIZE - (write_addr + to_write * sizeof(s32)))};
+ if (write_safe) [[likely]] {
+ auto ptr = memory.GetPointer(write_addr);
+ std::memcpy(ptr, &input[read_pos], to_write * sizeof(s32));
+ } else {
memory.WriteBlockUnsafe(send_buffer + target_write_offset * sizeof(s32),
- &input[write_pos], to_write * sizeof(s32));
+ &input[read_pos], to_write * sizeof(s32));
}
-
target_write_offset = (target_write_offset + to_write) % count_max;
write_count -= to_write;
- write_pos += to_write;
+ read_pos += to_write;
}
if (update_count) {
- send_info.write_offset = (send_info.write_offset + update_count) % count_max;
+ send_ptr->write_offset = (send_ptr->write_offset + update_count) % count_max;
}
- memory.WriteBlockUnsafe(send_info_, &send_info, sizeof(AuxInfo::AuxInfoDsp));
+ if (!host_safe) [[unlikely]] {
+ memory.WriteBlockUnsafe(send_info_, send_ptr, sizeof(AuxInfo::AuxInfoDsp));
+ }
return write_count_;
}
@@ -102,7 +135,7 @@ static u32 WriteAuxBufferDsp(Core::Memory::Memory& memory, const CpuAddr send_in
* Read the given memory at return_buffer into the output mix buffer, and update return_info_ if
* update_count is set, to notify the game that an update happened.
*
- * @param memory - Core memory for writing.
+ * @param memory - Core memory for reading.
* @param return_info_ - Meta information for where to read the mix buffer.
* @param return_buffer - Memory address to read the samples from.
* @param count_max - Maximum number of samples in the receiving buffer.
@@ -112,16 +145,21 @@ static u32 WriteAuxBufferDsp(Core::Memory::Memory& memory, const CpuAddr send_in
* @param update_count - If non-zero, send_info_ will be updated.
* @return Number of samples read.
*/
-static u32 ReadAuxBufferDsp(Core::Memory::Memory& memory, const CpuAddr return_info_,
- const CpuAddr return_buffer, const u32 count_max, std::span<s32> output,
- const u32 count_, const u32 read_offset, const u32 update_count) {
+static u32 ReadAuxBufferDsp(Core::Memory::Memory& memory, CpuAddr return_info_,
+ CpuAddr return_buffer, u32 count_max, std::span<s32> output,
+ u32 read_count_, u32 read_offset, u32 update_count) {
if (count_max == 0) {
return 0;
}
- if (count_ > count_max) {
+ if (read_count_ > count_max) {
LOG_ERROR(Service_Audio, "count must be smaller than count_max! count {}, count_max {}",
- count_, count_max);
+ read_count_, count_max);
+ return 0;
+ }
+
+ if (return_info_ == 0) {
+ LOG_ERROR(Service_Audio, "return_info_ is 0!");
return 0;
}
@@ -136,35 +174,49 @@ static u32 ReadAuxBufferDsp(Core::Memory::Memory& memory, const CpuAddr return_i
}
AuxInfo::AuxInfoDsp return_info{};
- memory.ReadBlockUnsafe(return_info_, &return_info, sizeof(AuxInfo::AuxInfoDsp));
+ auto return_ptr = &return_info;
+ bool host_safe = (return_info_ & Core::Memory::YUZU_PAGEMASK) <=
+ (Core::Memory::YUZU_PAGESIZE - sizeof(AuxInfo::AuxInfoDsp));
+
+ if (host_safe) [[likely]] {
+ return_ptr = memory.GetPointer<AuxInfo::AuxInfoDsp>(return_info_);
+ } else {
+ memory.ReadBlockUnsafe(return_info_, return_ptr, sizeof(AuxInfo::AuxInfoDsp));
+ }
- u32 target_read_offset{return_info.read_offset + read_offset};
+ u32 target_read_offset{return_ptr->read_offset + read_offset};
if (target_read_offset > count_max) {
return 0;
}
- u32 read_count{count_};
- u32 read_pos{0};
+ u32 read_count{read_count_};
+ u32 write_pos{0};
while (read_count > 0) {
u32 to_read{std::min(count_max - target_read_offset, read_count)};
-
- if (to_read > 0) {
+ const auto read_addr = return_buffer + target_read_offset * sizeof(s32);
+ bool read_safe{(read_addr & Core::Memory::YUZU_PAGEMASK) <=
+ (Core::Memory::YUZU_PAGESIZE - (read_addr + to_read * sizeof(s32)))};
+ if (read_safe) [[likely]] {
+ auto ptr = memory.GetPointer(read_addr);
+ std::memcpy(&output[write_pos], ptr, to_read * sizeof(s32));
+ } else {
memory.ReadBlockUnsafe(return_buffer + target_read_offset * sizeof(s32),
- &output[read_pos], to_read * sizeof(s32));
+ &output[write_pos], to_read * sizeof(s32));
}
-
target_read_offset = (target_read_offset + to_read) % count_max;
read_count -= to_read;
- read_pos += to_read;
+ write_pos += to_read;
}
if (update_count) {
- return_info.read_offset = (return_info.read_offset + update_count) % count_max;
+ return_ptr->read_offset = (return_ptr->read_offset + update_count) % count_max;
}
- memory.WriteBlockUnsafe(return_info_, &return_info, sizeof(AuxInfo::AuxInfoDsp));
+ if (!host_safe) [[unlikely]] {
+ memory.WriteBlockUnsafe(return_info_, return_ptr, sizeof(AuxInfo::AuxInfoDsp));
+ }
- return count_;
+ return read_count_;
}
void AuxCommand::Dump([[maybe_unused]] const ADSP::CommandListProcessor& processor,
@@ -189,7 +241,7 @@ void AuxCommand::Process(const ADSP::CommandListProcessor& processor) {
update_count)};
if (read != processor.sample_count) {
- std::memset(&output_buffer[read], 0, processor.sample_count - read);
+ std::memset(&output_buffer[read], 0, (processor.sample_count - read) * sizeof(s32));
}
} else {
ResetAuxBufferDsp(*processor.memory, send_buffer_info);
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 16ced4595..ff5502d87 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -225,6 +225,8 @@ add_library(core STATIC
hle/kernel/k_memory_manager.h
hle/kernel/k_memory_region.h
hle/kernel/k_memory_region_type.h
+ hle/kernel/k_object_name.cpp
+ hle/kernel/k_object_name.h
hle/kernel/k_page_bitmap.h
hle/kernel/k_page_buffer.cpp
hle/kernel/k_page_buffer.h
diff --git a/src/core/hle/kernel/init/init_slab_setup.cpp b/src/core/hle/kernel/init/init_slab_setup.cpp
index 571acf4b2..abdb5639f 100644
--- a/src/core/hle/kernel/init/init_slab_setup.cpp
+++ b/src/core/hle/kernel/init/init_slab_setup.cpp
@@ -16,6 +16,7 @@
#include "core/hle/kernel/k_event_info.h"
#include "core/hle/kernel/k_memory_layout.h"
#include "core/hle/kernel/k_memory_manager.h"
+#include "core/hle/kernel/k_object_name.h"
#include "core/hle/kernel/k_page_buffer.h"
#include "core/hle/kernel/k_port.h"
#include "core/hle/kernel/k_process.h"
@@ -49,6 +50,7 @@ namespace Kernel::Init {
HANDLER(KThreadLocalPage, \
(SLAB_COUNT(KProcess) + (SLAB_COUNT(KProcess) + SLAB_COUNT(KThread)) / 8), \
##__VA_ARGS__) \
+ HANDLER(KObjectName, (SLAB_COUNT(KObjectName)), ##__VA_ARGS__) \
HANDLER(KResourceLimit, (SLAB_COUNT(KResourceLimit)), ##__VA_ARGS__) \
HANDLER(KEventInfo, (SLAB_COUNT(KThread) + SLAB_COUNT(KDebug)), ##__VA_ARGS__) \
HANDLER(KDebug, (SLAB_COUNT(KDebug)), ##__VA_ARGS__) \
diff --git a/src/core/hle/kernel/k_object_name.cpp b/src/core/hle/kernel/k_object_name.cpp
new file mode 100644
index 000000000..df3a1c4c5
--- /dev/null
+++ b/src/core/hle/kernel/k_object_name.cpp
@@ -0,0 +1,102 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/kernel/k_object_name.h"
+
+namespace Kernel {
+
+KObjectNameGlobalData::KObjectNameGlobalData(KernelCore& kernel) : m_object_list_lock{kernel} {}
+KObjectNameGlobalData::~KObjectNameGlobalData() = default;
+
+void KObjectName::Initialize(KAutoObject* obj, const char* name) {
+ // Set member variables.
+ m_object = obj;
+ std::strncpy(m_name.data(), name, sizeof(m_name) - 1);
+ m_name[sizeof(m_name) - 1] = '\x00';
+
+ // Open a reference to the object we hold.
+ m_object->Open();
+}
+
+bool KObjectName::MatchesName(const char* name) const {
+ return std::strncmp(m_name.data(), name, sizeof(m_name)) == 0;
+}
+
+Result KObjectName::NewFromName(KernelCore& kernel, KAutoObject* obj, const char* name) {
+ // Create a new object name.
+ KObjectName* new_name = KObjectName::Allocate(kernel);
+ R_UNLESS(new_name != nullptr, ResultOutOfResource);
+
+ // Initialize the new name.
+ new_name->Initialize(obj, name);
+
+ // Check if there's an existing name.
+ {
+ // Get the global data.
+ KObjectNameGlobalData& gd{kernel.ObjectNameGlobalData()};
+
+ // Ensure we have exclusive access to the global list.
+ KScopedLightLock lk{gd.GetObjectListLock()};
+
+ // If the object doesn't exist, put it into the list.
+ KScopedAutoObject existing_object = FindImpl(kernel, name);
+ if (existing_object.IsNull()) {
+ gd.GetObjectList().push_back(*new_name);
+ R_SUCCEED();
+ }
+ }
+
+ // The object already exists, which is an error condition. Perform cleanup.
+ obj->Close();
+ KObjectName::Free(kernel, new_name);
+ R_THROW(ResultInvalidState);
+}
+
+Result KObjectName::Delete(KernelCore& kernel, KAutoObject* obj, const char* compare_name) {
+ // Get the global data.
+ KObjectNameGlobalData& gd{kernel.ObjectNameGlobalData()};
+
+ // Ensure we have exclusive access to the global list.
+ KScopedLightLock lk{gd.GetObjectListLock()};
+
+ // Find a matching entry in the list, and delete it.
+ for (auto& name : gd.GetObjectList()) {
+ if (name.MatchesName(compare_name) && obj == name.GetObject()) {
+ // We found a match, clean up its resources.
+ obj->Close();
+ gd.GetObjectList().erase(gd.GetObjectList().iterator_to(name));
+ KObjectName::Free(kernel, std::addressof(name));
+ R_SUCCEED();
+ }
+ }
+
+ // We didn't find the object in the list.
+ R_THROW(ResultNotFound);
+}
+
+KScopedAutoObject<KAutoObject> KObjectName::Find(KernelCore& kernel, const char* name) {
+ // Get the global data.
+ KObjectNameGlobalData& gd{kernel.ObjectNameGlobalData()};
+
+ // Ensure we have exclusive access to the global list.
+ KScopedLightLock lk{gd.GetObjectListLock()};
+
+ return FindImpl(kernel, name);
+}
+
+KScopedAutoObject<KAutoObject> KObjectName::FindImpl(KernelCore& kernel, const char* compare_name) {
+ // Get the global data.
+ KObjectNameGlobalData& gd{kernel.ObjectNameGlobalData()};
+
+ // Try to find a matching object in the global list.
+ for (const auto& name : gd.GetObjectList()) {
+ if (name.MatchesName(compare_name)) {
+ return name.GetObject();
+ }
+ }
+
+ // There's no matching entry in the list.
+ return nullptr;
+}
+
+} // namespace Kernel
diff --git a/src/core/hle/kernel/k_object_name.h b/src/core/hle/kernel/k_object_name.h
new file mode 100644
index 000000000..b7f943134
--- /dev/null
+++ b/src/core/hle/kernel/k_object_name.h
@@ -0,0 +1,86 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include <array>
+#include <memory>
+#include <boost/intrusive/list.hpp>
+
+#include "core/hle/kernel/k_light_lock.h"
+#include "core/hle/kernel/slab_helpers.h"
+#include "core/hle/kernel/svc_results.h"
+
+namespace Kernel {
+
+class KObjectNameGlobalData;
+
+class KObjectName : public KSlabAllocated<KObjectName>, public boost::intrusive::list_base_hook<> {
+public:
+ explicit KObjectName(KernelCore&) {}
+ virtual ~KObjectName() = default;
+
+ static constexpr size_t NameLengthMax = 12;
+ using List = boost::intrusive::list<KObjectName>;
+
+ static Result NewFromName(KernelCore& kernel, KAutoObject* obj, const char* name);
+ static Result Delete(KernelCore& kernel, KAutoObject* obj, const char* name);
+
+ static KScopedAutoObject<KAutoObject> Find(KernelCore& kernel, const char* name);
+
+ template <typename Derived>
+ static Result Delete(KernelCore& kernel, const char* name) {
+ // Find the object.
+ KScopedAutoObject obj = Find(kernel, name);
+ R_UNLESS(obj.IsNotNull(), ResultNotFound);
+
+ // Cast the object to the desired type.
+ Derived* derived = obj->DynamicCast<Derived*>();
+ R_UNLESS(derived != nullptr, ResultNotFound);
+
+ // Check that the object is closed.
+ R_UNLESS(derived->IsServerClosed(), ResultInvalidState);
+
+ return Delete(kernel, obj.GetPointerUnsafe(), name);
+ }
+
+ template <typename Derived>
+ requires(std::derived_from<Derived, KAutoObject>)
+ static KScopedAutoObject<Derived> Find(KernelCore& kernel, const char* name) {
+ return Find(kernel, name);
+ }
+
+private:
+ static KScopedAutoObject<KAutoObject> FindImpl(KernelCore& kernel, const char* name);
+
+ void Initialize(KAutoObject* obj, const char* name);
+
+ bool MatchesName(const char* name) const;
+ KAutoObject* GetObject() const {
+ return m_object;
+ }
+
+private:
+ std::array<char, NameLengthMax> m_name{};
+ KAutoObject* m_object{};
+};
+
+class KObjectNameGlobalData {
+public:
+ explicit KObjectNameGlobalData(KernelCore& kernel);
+ ~KObjectNameGlobalData();
+
+ KLightLock& GetObjectListLock() {
+ return m_object_list_lock;
+ }
+
+ KObjectName::List& GetObjectList() {
+ return m_object_list;
+ }
+
+private:
+ KLightLock m_object_list_lock;
+ KObjectName::List m_object_list;
+};
+
+} // namespace Kernel
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index b1922659d..3a68a5633 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -29,6 +29,7 @@
#include "core/hle/kernel/k_hardware_timer.h"
#include "core/hle/kernel/k_memory_layout.h"
#include "core/hle/kernel/k_memory_manager.h"
+#include "core/hle/kernel/k_object_name.h"
#include "core/hle/kernel/k_page_buffer.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/k_resource_limit.h"
@@ -84,6 +85,7 @@ struct KernelCore::Impl {
InitializeShutdownThreads();
InitializePhysicalCores();
InitializePreemption(kernel);
+ InitializeGlobalData(kernel);
// Initialize the Dynamic Slab Heaps.
{
@@ -194,6 +196,8 @@ struct KernelCore::Impl {
}
}
+ object_name_global_data.reset();
+
// Ensure that the object list container is finalized and properly shutdown.
global_object_list_container->Finalize();
global_object_list_container.reset();
@@ -363,6 +367,10 @@ struct KernelCore::Impl {
}
}
+ void InitializeGlobalData(KernelCore& kernel) {
+ object_name_global_data = std::make_unique<KObjectNameGlobalData>(kernel);
+ }
+
void MakeApplicationProcess(KProcess* process) {
application_process = process;
}
@@ -838,6 +846,8 @@ struct KernelCore::Impl {
std::unique_ptr<KAutoObjectWithListContainer> global_object_list_container;
+ std::unique_ptr<KObjectNameGlobalData> object_name_global_data;
+
/// Map of named ports managed by the kernel, which can be retrieved using
/// the ConnectToPort SVC.
std::unordered_map<std::string, ServiceInterfaceFactory> service_interface_factory;
@@ -1138,6 +1148,10 @@ void KernelCore::SetCurrentEmuThread(KThread* thread) {
impl->SetCurrentEmuThread(thread);
}
+KObjectNameGlobalData& KernelCore::ObjectNameGlobalData() {
+ return *impl->object_name_global_data;
+}
+
KMemoryManager& KernelCore::MemoryManager() {
return *impl->memory_manager;
}
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index a236e6b42..6e0668f7f 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -44,6 +44,8 @@ class KHardwareTimer;
class KLinkedListNode;
class KMemoryLayout;
class KMemoryManager;
+class KObjectName;
+class KObjectNameGlobalData;
class KPageBuffer;
class KPageBufferSlabHeap;
class KPort;
@@ -240,6 +242,9 @@ public:
/// Register the current thread as a non CPU core thread.
void RegisterHostThread(KThread* existing_thread = nullptr);
+ /// Gets global data for KObjectName.
+ KObjectNameGlobalData& ObjectNameGlobalData();
+
/// Gets the virtual memory manager for the kernel.
KMemoryManager& MemoryManager();
@@ -372,6 +377,8 @@ public:
return slab_heap_container->page_buffer;
} else if constexpr (std::is_same_v<T, KThreadLocalPage>) {
return slab_heap_container->thread_local_page;
+ } else if constexpr (std::is_same_v<T, KObjectName>) {
+ return slab_heap_container->object_name;
} else if constexpr (std::is_same_v<T, KSessionRequest>) {
return slab_heap_container->session_request;
} else if constexpr (std::is_same_v<T, KSecureSystemResource>) {
@@ -443,6 +450,7 @@ private:
KSlabHeap<KDeviceAddressSpace> device_address_space;
KSlabHeap<KPageBuffer> page_buffer;
KSlabHeap<KThreadLocalPage> thread_local_page;
+ KSlabHeap<KObjectName> object_name;
KSlabHeap<KSessionRequest> session_request;
KSlabHeap<KSecureSystemResource> secure_system_resource;
KSlabHeap<KEventInfo> event_info;
diff --git a/src/core/hle/kernel/svc/svc_port.cpp b/src/core/hle/kernel/svc/svc_port.cpp
index 2b7cebde5..2f9bfcb52 100644
--- a/src/core/hle/kernel/svc/svc_port.cpp
+++ b/src/core/hle/kernel/svc/svc_port.cpp
@@ -5,6 +5,7 @@
#include "core/core.h"
#include "core/hle/kernel/k_client_port.h"
#include "core/hle/kernel/k_client_session.h"
+#include "core/hle/kernel/k_object_name.h"
#include "core/hle/kernel/k_port.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/svc.h"
@@ -74,10 +75,57 @@ Result ConnectToPort(Core::System& system, Handle* out_handle, Handle port) {
R_THROW(ResultNotImplemented);
}
-Result ManageNamedPort(Core::System& system, Handle* out_server_handle, uint64_t name,
+Result ManageNamedPort(Core::System& system, Handle* out_server_handle, uint64_t user_name,
int32_t max_sessions) {
- UNIMPLEMENTED();
- R_THROW(ResultNotImplemented);
+ // Copy the provided name from user memory to kernel memory.
+ std::array<char, KObjectName::NameLengthMax> name{};
+ system.Memory().ReadBlock(user_name, name.data(), sizeof(name));
+
+ // Validate that sessions and name are valid.
+ R_UNLESS(max_sessions >= 0, ResultOutOfRange);
+ R_UNLESS(name[sizeof(name) - 1] == '\x00', ResultOutOfRange);
+
+ if (max_sessions > 0) {
+ // Get the current handle table.
+ auto& handle_table = GetCurrentProcess(system.Kernel()).GetHandleTable();
+
+ // Create a new port.
+ KPort* port = KPort::Create(system.Kernel());
+ R_UNLESS(port != nullptr, ResultOutOfResource);
+
+ // Initialize the new port.
+ port->Initialize(max_sessions, false, "");
+
+ // Register the port.
+ KPort::Register(system.Kernel(), port);
+
+ // Ensure that our only reference to the port is in the handle table when we're done.
+ SCOPE_EXIT({
+ port->GetClientPort().Close();
+ port->GetServerPort().Close();
+ });
+
+ // Register the handle in the table.
+ R_TRY(handle_table.Add(out_server_handle, std::addressof(port->GetServerPort())));
+ ON_RESULT_FAILURE {
+ handle_table.Remove(*out_server_handle);
+ };
+
+ // Create a new object name.
+ R_TRY(KObjectName::NewFromName(system.Kernel(), std::addressof(port->GetClientPort()),
+ name.data()));
+ } else /* if (max_sessions == 0) */ {
+ // Ensure that this else case is correct.
+ ASSERT(max_sessions == 0);
+
+ // If we're closing, there's no server handle.
+ *out_server_handle = InvalidHandle;
+
+ // Delete the object.
+ R_TRY(KObjectName::Delete<KClientPort>(system.Kernel(), name.data()));
+ }
+
+ R_SUCCEED();
}
Result ConnectToNamedPort64(Core::System& system, Handle* out_handle, uint64_t name) {
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp
index 7195f2bc1..614d61db4 100644
--- a/src/video_core/engines/maxwell_3d.cpp
+++ b/src/video_core/engines/maxwell_3d.cpp
@@ -186,6 +186,7 @@ bool Maxwell3D::IsMethodExecutable(u32 method) {
case MAXWELL3D_REG_INDEX(launch_dma):
case MAXWELL3D_REG_INDEX(inline_data):
case MAXWELL3D_REG_INDEX(fragment_barrier):
+ case MAXWELL3D_REG_INDEX(invalidate_texture_data_cache):
case MAXWELL3D_REG_INDEX(tiled_cache_barrier):
return true;
default:
@@ -375,6 +376,9 @@ void Maxwell3D::ProcessMethodCall(u32 method, u32 argument, u32 nonshadow_argume
return;
case MAXWELL3D_REG_INDEX(fragment_barrier):
return rasterizer->FragmentBarrier();
+ case MAXWELL3D_REG_INDEX(invalidate_texture_data_cache):
+ rasterizer->InvalidateGPUCache();
+ return rasterizer->WaitForIdle();
case MAXWELL3D_REG_INDEX(tiled_cache_barrier):
return rasterizer->TiledCacheBarrier();
default:
diff --git a/src/video_core/host1x/codecs/codec.cpp b/src/video_core/host1x/codecs/codec.cpp
index 42e7d6e4f..3e9022dce 100644
--- a/src/video_core/host1x/codecs/codec.cpp
+++ b/src/video_core/host1x/codecs/codec.cpp
@@ -152,6 +152,8 @@ bool Codec::CreateGpuAvDevice() {
void Codec::InitializeAvCodecContext() {
av_codec_ctx = avcodec_alloc_context3(av_codec);
av_opt_set(av_codec_ctx->priv_data, "tune", "zerolatency", 0);
+ av_codec_ctx->thread_count = 0;
+ av_codec_ctx->thread_type &= ~FF_THREAD_FRAME;
}
void Codec::InitializeGpuDecoder() {
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index 31209fb2e..db68ed259 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -1103,6 +1103,7 @@ void Config::SaveValues() {
SaveRendererValues();
SaveAudioValues();
SaveSystemValues();
+ qt_config->sync();
}
void Config::SaveAudioValues() {
diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp
index 22aa19c56..c21828b1d 100644
--- a/src/yuzu/game_list.cpp
+++ b/src/yuzu/game_list.cpp
@@ -870,6 +870,7 @@ void GameList::ToggleFavorite(u64 program_id) {
tree_view->setRowHidden(0, item_model->invisibleRootItem()->index(), true);
}
}
+ SaveConfig();
}
void GameList::AddFavorite(u64 program_id) {
diff --git a/src/yuzu/game_list.h b/src/yuzu/game_list.h
index f7ff93ed9..64e5af4c1 100644
--- a/src/yuzu/game_list.h
+++ b/src/yuzu/game_list.h
@@ -122,6 +122,7 @@ signals:
void AddDirectory();
void ShowList(bool show);
void PopulatingCompleted();
+ void SaveConfig();
private slots:
void OnItemExpanded(const QModelIndex& item);
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index a689a32db..f233b065e 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -1279,6 +1279,7 @@ void GMainWindow::ConnectWidgetEvents() {
connect(game_list, &GameList::ShowList, this, &GMainWindow::OnGameListShowList);
connect(game_list, &GameList::PopulatingCompleted,
[this] { multiplayer_state->UpdateGameList(game_list->GetModel()); });
+ connect(game_list, &GameList::SaveConfig, this, &GMainWindow::OnSaveConfig);
connect(game_list, &GameList::OpenPerGameGeneralRequested, this,
&GMainWindow::OnGameListOpenPerGameProperties);
@@ -2662,6 +2663,8 @@ void GMainWindow::OnGameListAddDirectory() {
} else {
LOG_WARNING(Frontend, "Selected directory is already in the game list");
}
+
+ OnSaveConfig();
}
void GMainWindow::OnGameListShowList(bool show) {
@@ -3023,8 +3026,10 @@ void GMainWindow::OnRestartGame() {
if (!system->IsPoweredOn()) {
return;
}
- // Make a copy since BootGame edits game_path
- BootGame(QString(current_game_path));
+ // Make a copy since ShutdownGame edits game_path
+ const auto current_game = QString(current_game_path);
+ ShutdownGame();
+ BootGame(current_game);
}
void GMainWindow::OnPauseGame() {
@@ -3388,6 +3393,7 @@ void GMainWindow::OnConfigureTas() {
return;
} else if (result == QDialog::Accepted) {
dialog.ApplyConfiguration();
+ OnSaveConfig();
}
}